package org.example.utils;

import lombok.Getter;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.example.enums.BaseEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author wf
 * @date 2020-11-12 3:24 PM
 */
public class HttpClientUtil {
    private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
    
    /**
     * HTTP请求时间
     */
    private static final Integer HTTP_TIMEOUT = 1000 * 30;

    /**
     * get请求
     * @param url  url地址
     * @param params 参数
     * @return
     */
    public static String doGet(String url, Map<String, String> params) {
        String resultString = null;
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            List<NameValuePair> paramList = new ArrayList<>();
            URIBuilder builder = new URIBuilder(url);
            if(params != null){
                params.forEach((key, value) -> paramList.add(new BasicNameValuePair(key, value)));
            }
            builder.addParameters(paramList);
            httpClient = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet(builder.build());
            httpGet.releaseConnection();
            httpGet.setHeader("charset", "UTF-8");
            RequestConfig config = RequestConfig.custom().setConnectTimeout(HTTP_TIMEOUT).setSocketTimeout(HTTP_TIMEOUT).build();
            httpGet.setConfig(config);
            //模拟表单
            response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if(statusCode == HttpStatus.SC_OK){
                resultString = EntityUtils.toString(response.getEntity(), "utf-8");
                logger.info("GET请求成功! url = {}, params = {}, resultString = {}", url, params, resultString);
            }else {
                logger.error("GET请求失败! url = {}, params = {}, HttpStatus = {}", url, params, statusCode);
            }
        } catch (Exception e) {
            logger.error("GET请求失败! url = {}, params = {}, errorMasg = {}", url, params, e);
        }finally {
            closeResource(httpClient, response, HttpMethodEnum.GET);
        }
        return resultString;
    }

    /**
     * 无参数get请求
     * @param url
     * @return
     */
    public static String doGet(String url) {
        String resultString = null;
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet(url);
            httpGet.setHeader("charset", "UTF-8");
            RequestConfig config = RequestConfig.custom().setConnectTimeout(HTTP_TIMEOUT).setSocketTimeout(HTTP_TIMEOUT).build();
            httpGet.setConfig(config);
            // 模拟表单
            response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if(statusCode == HttpStatus.SC_OK){
                resultString = EntityUtils.toString(response.getEntity(), "utf-8");
                logger.info("GET请求成功! url = {}, resultString = {}", url, resultString);
            }else {
                logger.error("GET请求失败! url = {}, HttpStatus = {}", url, statusCode);
            }
        } catch (Exception e) {
            logger.error("GET请求失败! url = {}, errorMasg = {}", url, e);
        }finally {
            closeResource(httpClient, response, HttpMethodEnum.GET);
        }
        return resultString;
    }

    /**
     * post请求(params形式发送请求)
     * @param url  url地址
     * @param params  参数
     * @param contentType
     * @return
     */
    public static String doPost(String url, Map<String, String> params, String contentType) {
        List<NameValuePair> paramList = new ArrayList<>();
        if(params != null){
            params.forEach((key, value) -> paramList.add(new BasicNameValuePair(key, value)));
        }
        String resultString = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        HttpPost httpPost = null;
        try {
            httpPost = new HttpPost(url);
            httpPost.setHeader("Content-Type", contentType);
            RequestConfig config = RequestConfig.custom().setConnectTimeout(HTTP_TIMEOUT).setSocketTimeout(HTTP_TIMEOUT).build();
            httpPost.setConfig(config);
            //模拟表单
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
            httpPost.setEntity(entity);
            response = httpClient.execute(httpPost);
            if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
                logger.info("POST请求成功! url = {}, params = {}, resultString = {}", url, params, resultString);
            }else {
                logger.error("POST请求失败! url = {}, params = {}, HttpStatus = {}", url, params, response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            logger.error("POST请求失败! url = {}, params = {}, errorMasg = {}", url, params, e);
        }finally {
            closeResource(httpClient, response, HttpMethodEnum.POST);
        }
        return resultString;
    }

    /**
     * post请求(json参数形式发送请求)
     * @param url
     * @param paramsJson
     * @return
     */
    public static String doPost(String url, String paramsJson) {
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = null;
        CloseableHttpResponse response = null;
        try {
            httpPost = new HttpPost(url);
            httpPost.setHeader("Content-Type", "application/json; charset=UTF-8");
            RequestConfig config = RequestConfig.custom().setConnectTimeout(HTTP_TIMEOUT).setSocketTimeout(HTTP_TIMEOUT).build();
            httpPost.setConfig(config);
            //参数
            StringEntity entity = new StringEntity(paramsJson, "UTF-8");
            httpPost.setEntity(entity);
            response = httpClient.execute(httpPost);
            if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
                result = EntityUtils.toString(response.getEntity(), "UTF-8");
                logger.info("POST请求成功! url = {}, params = {}, resultString = {}", url, paramsJson, result);
            }else {
                logger.error("POST请求失败! url = {}, params = {}, HttpStatus = {}", url, paramsJson, response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            logger.error("POST请求失败! url = {}, errorMasg = {}", url, e);
        }finally {
            closeResource(httpClient, response, HttpMethodEnum.POST);
        }
        return result;
    }

    /**
     * 资源关闭
     * @param httpClient
     * @param response
     */
    private static void closeResource(CloseableHttpClient httpClient, CloseableHttpResponse response, HttpMethodEnum method){
        try {
            if(httpClient != null){
                httpClient.close();
            }
            if(response != null){
                response.close();
            }
        } catch (IOException e) {
            logger.error("关闭{}请求异常!", method.desc);
        }
    }

    /**
     * 请求方式日志处理枚举
     */
    enum HttpMethodEnum implements BaseEnum {
        POST(1, "POST"),
        GET(2, "GET");
        
        @Getter
        int code;
        @Getter
        String desc;

        HttpMethodEnum(int code, String desc){
            this.code = code;
            this.desc = desc;
        }
    }
}
